// 071114;080505 alexch
//
// ==========  This file is under  LGPL, the GNU Lesser General Public Licence
// ==========  Dialing Lemmatizer (www.aot.ru)
// ==========  Copyright by Alexey Sokirko 
//
// ==========  Visual Studio project for 32/64 bit DLL-wrapper
// ==========  Created by Hulbee AG

#ifndef __STLFILEF_H_
#define __STLFILEF_H_

#include "StlSysF.h"
#include <stdio.h>

#ifndef ONLY_NATIVE
	#include <windows.h>
#endif

namespace StlFunc {

const static unsigned int MaxFileNameLen = 1024;

const static char DriveDelimiter = ':';
const static wchar_t DriveDelimiterW = L':';

const static char PathDelimiter = '\\';
const static wchar_t PathDelimiterW = L'\\';

wstr_t& IncludePathDelimiter(wstr_t &pathName);
str_t& IncludePathDelimiter(str_t &pathName);
/* example:
	in:		pathName == "c:\temp"
	out:	pathName == "c:\temp\"
*/

wstr_t& ExcludePathDelimiter(wstr_t &pathName);
str_t& ExcludePathDelimiter(str_t &pathName);
/* example:
	in:		pathName == "c:\temp\"
	out:	pathName == "c:\temp"
*/

wstr_t& ExtractFileDrive(const wstr_t &src, wstr_t &dst);
/* example 1:
	in:		src == "c:\temp\list.txt"
	out:	dst == "c:\"
   example 2:
	in:		src == "\\server_name\share_name\list.txt"
	out:	dst == "\\server_name\share_name\"
*/
wstr_t& ExtractFileDrive(wstr_t &pathName);

void ExtractFilePath(const wstr_t &src, wstr_t &dst);
/* example:
	in:		src == "c:\temp\list.txt"
	out:	dst == "c:\temp\"
*/
wstr_t& ExtractFilePath(wstr_t &fileName);
/* example:
	in:		fileName == "c:\temp\list.txt"
	out:	fileName == "c:\temp\"
*/

void ExtractFileName(const wstr_t &src, wstr_t &dst);
/* example:
	in:		src == "c:\temp\list.txt"
	out:	dst == "list.txt"
*/
wstr_t& ExtractFileName(wstr_t &fileName);
/* example:
	in:		fileName == "c:\temp\list.txt"
	out:	fileName == "list.txt"
*/

void ParseFileName(const wchar_t *fullName, wstr_t &fileName, wstr_t &filePath);
/* example:
	in:		fullName == "c:\temp\list.txt"
	out:	fileName == "list.txt", filePath == "c:\temp\"
*/

void ParseFileName(wstr_t &fileName, wstr_t &filePath);
/* example:
	in:		fileName == "c:\temp\list.txt"
	out:	fileName == "list.txt", filePath == "c:\temp\"
*/

void ExtractFileExt(const wstr_t &src, wstr_t &dst);
void ExtractFileExt(const str_t &src, str_t &dst);
/* example:
	in:		src == "c:\temp\list.txt"
	out:	dst == "txt"
*/
wstr_t& ExtractFileExt(wstr_t &fileName);
str_t& ExtractFileExt(str_t &fileName);
/* example:
	in:		fileName == "c:\temp\list.txt"
	out:	fileName == "txt"
*/

wstr_t GetFileExt(const wstr_t &src);
str_t GetFileExt(const str_t &src);
/* example:
	in:		fileName == "c:\temp\list.txt"
	return:	"txt"
*/

wstr_t& ExcludeFileExt(wstr_t &fileName);
str_t& ExcludeFileExt(str_t &fileName);
/* example:
	in:		fileName == "c:\temp\list.txt"
	out:	fileName == "c:\temp\list"
*/

wstr_t& ChangeFileExt(wstr_t &fileName, const wstr_t &newExt);
str_t& ChangeFileExt(str_t &fileName, const str_t &newExt);
/* example 1:
	in:		fileName == "c:\temp\list.txt", newExt == "doc"
	out:	fileName == "c:\temp\list.doc"
   example 2:
	in:		fileName == "c:\temp\list.txt", newExt == ""
	out:	fileName == "c:\temp\list"
   comment: newExt can start from '.' or not - it doesn't matter
*/

#ifndef ONLY_NATIVE

bool EqualFileNames(const wstr_t &name1, const wstr_t &name2);
// checks file names (without paths) are the same
/* example:
	in:		name1 == "c:\temp\list.txt"
			name2 == "d:\LIST.TXT"
	return:	true
*/

bool ExpandPathName(wstr_t &pathName);
// wrapper for Win32 function GetFullPathName

//void GetLongPath(wstr_t &pathName);
/* converts a (possibly) short file or folder name pathName to long name; if
   the file or folder doesn't exist then the result is undefined;
  example 1:
	in:		pathName == "C:\DOCUME~1\admin\LOCALS~1\Temp\"
	out:	pathName == "C:\Documents and Settings\admin\Local Settings\Temp\"
   example 2:
	in:		pathName == "C:\DOCUME~1\admin\LOCALS~1\Temp\LongFi~1.txt"
	out:	pathName == "C:\Documents and Settings\admin\Local Settings\Temp\LongFileName.txt"
*/

bool GetLongPath(wstr_t &pathName);
// wrapper for Win32 function GetLongPathName

bool GetModuleFile(wstr_t &fileName, HMODULE hModule = 0, unsigned int *err = 0);
// wrapper for Win32 function GetModuleFileName

bool GetCurrentFolder(wstr_t &pathName);
// wrapper for Win32 function GetCurrentDirectory; ensures the path returned ends with PathDelimiter

bool GetTempFolder(wstr_t &pathName);
// wrapper for Win32 function GetTempPath; ensures the path returned ends with PathDelimiter

bool GetTempFile(wstr_t &fileName, const wchar_t *pathName = 0, const wchar_t *prefix = 0, unsigned int unique = 0);

bool CreateTempFolder(wstr_t &folderName, const wchar_t *pathName, unsigned int waitTimeMilliseconds = 500,
	unsigned int *err = 0, const wchar_t *prefix = 0, unsigned int unique = 0);

bool GetWindowsFolder(wstr_t &pathName);
// wrapper for Win32 function GetWindowsDirectory; ensures the path returned ends with PathDelimiter

bool GetSystemFolder(wstr_t &pathName);
// wrapper for Win32 function GetSystemDirectory; ensures the path returned ends with PathDelimiter

bool GetSystemWindowsFolder(wstr_t &pathName);
// wrapper for Win32 function GetSystemWindowsDirectory; ensures the path returned ends with PathDelimiter

bool FileExists(const wchar_t *fileName);
bool FileExists(const char *fileName);
// checks whether a file with the given name exists

bool DirectoryExists(const wchar_t *pathName);
bool DirectoryExists(const char *pathName);
// checks whether a directory with the given name exists

bool ForceDirectory(const wstr_t &dirName, unsigned int *err = 0);

bool ReadFromFile(const wchar_t *fileName, void *buf, unsigned int *size, unsigned int *err = 0);

__int64 GetFileSize(const wchar_t *fileName, unsigned int *err = 0);
__int64 GetFileSize(const char *fileName, unsigned int *err = 0);

#if(_WIN32_WINNT >= 0x0400)
bool GetFileInfo(const wchar_t *fileName, LPBY_HANDLE_FILE_INFORMATION fileInfo, unsigned int *err = 0);
bool GetFileInfo(const char *fileName, LPBY_HANDLE_FILE_INFORMATION fileInfo, unsigned int *err = 0);
#endif

bool ForceDeleteFile(const wchar_t *fileName);
bool ForceDeleteFolder(const wchar_t *folderName);
// allows to delete read-only/hidden/system files or folders

bool FileClearReadOnlyAttr(const wchar_t *fileName);

bool SetLastWriteTime(const wchar_t *fileName, const FILETIME* lastWriteTime, unsigned int *err = 0);

bool WideFileName2Ansi(const wchar_t *wideName, str_t &ansiName);
// returns ANSI file name corresponding to the given Unicode file name; the file must exists

bool GetDirList(const wchar_t *dirName, wstrvec_t &list, const wchar_t *mask = 0, bool files = true,
	unsigned int *err = 0);

bool AddDirList(const wchar_t *dirName, wstrvec_t &list, const wchar_t *mask = 0, bool files = true,
	unsigned int *err = 0);

enum DirectoryElement {
	deAny,
	deFile,
	deDirectory
};

bool DirectoryContains(const wchar_t *dirName, const wchar_t *fileMask = L"*", DirectoryElement acceptWhat = deAny);
// checks whether 'dirName' directory contains at least one file and/or subdirectory (depending on 'acceptWhat'
// value) which name matches 'fileMask'

#if(_WIN32_WINNT >= 0x0400)
bool CopyFolder(const wchar_t *sourceFolder, const wchar_t *targetFolder, const wchar_t *fileMask = L"*",
	bool recursively = true, LPPROGRESS_ROUTINE progress = 0, LPVOID context = 0, unsigned int *err = 0);
#endif

bool DeleteFolderRecursively(const wchar_t *dirName);

__int64 GetFolderSize(const wchar_t *dirName, const wchar_t *fileMask = L"*", bool recursive = true,
	unsigned int *err = 0);

class FileEraser {
protected:
	wstr_t m_fileName;
public:
	FileEraser(wstr_t &fileName): m_fileName(fileName) {}
	FileEraser(const wchar_t *fileName): m_fileName(fileName) {}
	FileEraser() {}
	void Set(wstr_t &fileName)
	{
		m_fileName = fileName;
	}
	void Set(const wchar_t *fileName)
	{
		m_fileName = fileName;
	}
	~FileEraser()
	{
		if (!m_fileName.empty())
			DeleteFileW(m_fileName.c_str());
	}	
};

class DirectoryEraser {
protected:
	wstr_t m_dirName;
public:
	DirectoryEraser(wstr_t &dirName): m_dirName(dirName) {}
	DirectoryEraser(const wchar_t *dirName): m_dirName(dirName) {}
	DirectoryEraser() {}
	void Set(wstr_t &dirName)
	{
		m_dirName = dirName;
	}
	void Set(const wchar_t *dirName)
	{
		m_dirName = dirName;
	}
	~DirectoryEraser()
	{
		if (!m_dirName.empty())
			RemoveDirectoryW(m_dirName.c_str());
	}	
};

class RecursiveDirectoryEraser {
protected:
	wstr_t m_dirName;
public:
	RecursiveDirectoryEraser(wstr_t &dirName): m_dirName(dirName) {}
	RecursiveDirectoryEraser(const wchar_t *dirName): m_dirName(dirName) {}
	RecursiveDirectoryEraser() {}
	void Set(wstr_t &dirName)
	{
		m_dirName = dirName;
	}
	void Set(const wchar_t *dirName)
	{
		m_dirName = dirName;
	}
	~RecursiveDirectoryEraser()
	{
		if (!m_dirName.empty())
			DeleteFolderRecursively(m_dirName.c_str());
	}	
};

class StdIoFile {
protected:
	FILE *m_f;
	bool m_unicode;
public:
	StdIoFile(): m_f(0), m_unicode(false) {}
	virtual ~StdIoFile()
	{
		Close();
	}
	bool Close();
	bool Unicode()
	{
		return m_unicode;
	}
	bool Eof()
	{
		return feof(m_f) != 0;
	}
	bool Error()
	{
		return ferror(m_f) != 0;
	}
};

class TextFileReader: public StdIoFile {
protected:
	char buf[2048];
public:
	enum TextMode {
		tmAnsi,
		tmUtf16,
		tmAuto
	};
	bool Open(const wchar_t *fileName, TextMode textMode);
	bool GetStr(wstr_t &w);
	TextFileReader& operator>>(wstr_t &w)
	{
		GetStr(w);
		return *this;
	}
};

class TextFileWriter: public StdIoFile {
public:
	bool Create(const wchar_t *fileName, bool unicode = false);
	bool PutStr(const wchar_t *w);
	bool PutStr(const wstr_t &w)
	{
		return PutStr(w.c_str());
	}
	bool PutLine(const wchar_t *w);
	bool PutLine(const wstr_t &w)
	{
		return PutLine(w.c_str());
	}
	TextFileWriter& operator<<(const wchar_t *w)
	{
		PutStr(w);
		return *this;
	}
	bool PutStr(const char *s);
	bool PutStr(const str_t &s)
	{
		return PutStr(s.c_str());
	}
	bool PutLine(const char *s);
	bool PutLine(const str_t &s)
	{
		return PutLine(s.c_str());
	}
	TextFileWriter& operator<<(const char *s)
	{
		PutStr(s);
		return *this;
	}
};

class FileListEraser {
protected:
	wstrvec_t m_files;
public:
	FileListEraser() {}
	~FileListEraser() { Erase(); }
	void Add(wstr_t fileName)
	{
		m_files.push_back(fileName);
	}
	void Set(const wstrvec_t &files);
	bool Pop()
	{
		if (m_files.empty())
			return false;
		m_files.pop_back();
		return true;
	}
	bool Erase(); // tries to erase all files which names were added
	void Cancel() // clears the internal file list without erasing the files
	{
		m_files.clear();
	}
};

#endif // ONLY_NATIVE

} // StlFunc

#endif
